'''
大气数传工程参数遥测源码转事后处理源码程序

数传工程参数遥测源码从FTP上下载 每帧(每行)768字节
事后处理源码 每帧(每行)544字节
将每行768字节去除末尾256字节 再在起始列前增加32字节 构成544字节

增加的32字节内容分为两类 固定字符和时间信息
1.固定字符直接填充即可 
2.时间信息需要在512字节中找到6字节时间信息(J2000格式)转化为整秒
再将该整秒值以1970年1月1日零时为基准转化为积秒 形成4字节保存

增加固定填充字符和时间信息后 544字节即可被事后处理使用

补充 该程序仅提供实时遥测转换 实时延时混合拼接未实现 
考虑到延时遥测数据少 忽略该数据可以接收
'''

from glob import glob
import numpy as np
import calendar
import time
import os


'''
numpy的6字节转十进制
输入 sdat numpy的6字节数据 
输出 十进制整数
'''
def str6_to_uint(sdat):
    foo = ''
    for i in range(6):  
        foo = foo + f'{sdat[i]:02x}'  # 02x表示十六进制显示 如果只有一位则补零
    res = int(foo, base=16) 
    return res


'''
星上时间转地面时间函数
输入 sat_time--numpy数组 星上6字节 J2000格式的数据
输出 res--List类型 地面4字节 整秒数据 小端格式 
    time_str--年月日时分秒字符串 用于产生文件名
算法 J2000格式的数据转为时分秒 再转换为整秒
'''
def time_convert(sat_time):
    sat_time_J2000 = str6_to_uint(sat_time) / 10000 # 转为整秒    
    y2000 = calendar.timegm((2000, 1, 1, 12, 0, 0))  # 计算J2000距离1970年有多少秒
    ground_time_dec = y2000 + int(sat_time_J2000)
    time_str = time.strftime('%Y%m%d%H%M%S', time.gmtime(ground_time_dec))
    ground_time_hex = f'{ground_time_dec:x}'  # 转十六进制
    # 组成4字节时间码
    res = [0,0,0,0]
    res[0] = int(ground_time_hex[6:8], base=16)
    res[1] = int(ground_time_hex[4:6], base=16)
    res[2] = int(ground_time_hex[2:4], base=16)
    res[3] = int(ground_time_hex[0:2], base=16)    
    return res, time_str


'''
帧去回卷函数 取出帧时间进行计算 如果小于上一帧相等 则去除该行
输入 yc_dat遥测源码 N行544列
输出 去重的遥测源码
'''
def remove_rollback(yc_dat):
    row,_ = yc_dat.shape
    vc_time_last = 0  # 上次记录的帧时间
    rm_row_number = list()
    for cnt in range(row):
        vc_time = str6_to_uint(yc_dat[cnt, 13:19])
        
        # # 去重和回卷
        # if vc_time <= vc_time_last:  # 如果当前时间小于等于上帧时间 删除该帧
        #     rm_row_number.append(cnt)
        # else:  # 如果大于 记录当前时间 作为下次比较
        #     vc_time_last = vc_time
        
        # 仅去回卷
        if vc_time < vc_time_last:  # 如果当前时间小于等于上帧时间 删除该帧
            rm_row_number.append(cnt)
        elif vc_time == vc_time_last:  # 如果当前时间小于等于上帧时间 删除上一帧
            rm_row_number.append(cnt-1)        
        else:  # 如果大于 记录当前时间 作为下次比较
            vc_time_last = vc_time
            
                
    yc_dat = np.delete(yc_dat, rm_row_number, axis=0)
    return yc_dat


'''
对每个SatYC文件进行整理
1. 形成512字节全球遥测
2. 实时遥测或者延时遥测提取
3. 找到数据开始的时间信息
'''
def satyc_check():
    print('SatYC文件整理中')
    current_cwd = os.getcwd()
    os.chdir('tm_ycdat')    
    file_list = glob('*.SatYC')
    
    # 判断文件是否存在 只有1个则更名
    if len(file_list) == 0:
        print('未找到SatYC文件 文件整理结束')
        return 
    
    # 有SatYC文件 
    for fname in file_list:
        yc_dat = np.fromfile(fname, dtype=np.uint8)
        yc_dat = yc_dat.reshape(int(len(yc_dat)/768), 768)
        # 取前512列字节 即形成全球遥测 
        yc_dat = yc_dat[:, 0:512]   
        # 筛选实时遥测或者延时遥测
        yc_dat = yc_dat[yc_dat[:,9] == 0x00]  #实时
        # yc_dat = yc_dat[yc_dat[:,9] == 0x80]  #延时
        
        # 提取时间信息 用于文件夹
        _, time_start = time_convert(yc_dat[0, 13:19])
        # 文件保存       
        now = time.strftime('%M%S', time.localtime(time.time()))
        fname = f"{time_start}_{fname[0:23]}_{now}.tmp"
        yc_dat.tofile(fname)  # 遥测源码保存
        print(f'遥测源码{fname}已生成')
        
    os.chdir(current_cwd)
    
    print(f'共计{len(file_list)}个遥测文件整理完成')


'''
tmp文件合并去重函数
'''
def tmp_concat():
    print('tmp文件合并中')
    current_cwd = os.getcwd()
    os.chdir('tm_ycdat')    
    file_list = glob('*.tmp')
    
    # 判断文件是否存在 只有1个则更名
    if len(file_list) == 0:
        print('未找到tmp文件 停止合并')
        return
    
    # 将文件读入并组合
    all_tmp = np.fromfile(file_list[0], dtype=np.uint8)
    all_tmp = all_tmp.reshape(int(len(all_tmp)/512), 512)  
    
    # 合并所有遥测源码
    for cnt in range(1, len(file_list)): # 从1开始
        foo = np.fromfile(file_list[cnt], dtype=np.uint8)
        foo = foo.reshape(int(len(foo)/512), 512)
        all_tmp = np.row_stack((all_tmp, foo)) 

    # 数据去重 去回卷
    all_tmp = remove_rollback(all_tmp)
    # 输出文件名生成
    now = time.strftime('%M%S', time.localtime(time.time()))
    fileout_name = f"SATYC_{file_list[0][0:14]}_{now}.dat"  
    # all_tmp.tofile(fileout_name)  # 遥测源码保存

    # print(f'合并后的遥测源码{fileout_name}已保存')

    os.chdir(current_cwd)
    print(f'遥测源码合并去重完成')
    return all_tmp, fileout_name


'''
工程遥测转码函数 转码后供事后处理代码调用
输入 yc_dat--去重帧的遥测源码 N行512列 numpy类型
    fname-- 生成的遥测名称 str类型
输出 无 dat文件
算法 每行增加32字节 包含固定字符和时间信息
'''
def form_dat_file(yc_dat, fname):
    print('SATYC转DAT文件进行中')    
    row,_ = yc_dat.shape  # 获取行信息
    header = np.zeros([row, 32], dtype=np.uint8)  # 构造前32字节
    # 固定位置填充固定值
    header[:, 0] = 0x90  
    header[:, 1] = 0xEB
    header[:, 2] = 0x02
    header[:, 23] = 0x02
    # 合并成544列 形成地面遥测帧
    ground_dat = np.column_stack((header, yc_dat))   
    # 遍历每一行 增加时间信息
    for row_cnt in range(row):          
        foo, _ = time_convert(ground_dat[row_cnt, 45:51]) 
        ground_dat[row_cnt, 16] = foo[0]
        ground_dat[row_cnt, 17] = foo[1]
        ground_dat[row_cnt, 18] = foo[2]
        ground_dat[row_cnt, 19] = foo[3]
    
    # 文件保存
    current_cwd = os.getcwd()
    os.chdir('tm_ycdat')
    ground_dat.tofile(fname)  # 遥测源码保存
    os.chdir(current_cwd)
    
    print(f'事后处理的文件生成{fname}')


'''
遥测源码 satyc转dat主函数
'''
def satyc2dat():
    satyc_check()
    yc, fname = tmp_concat()
    form_dat_file(yc, fname)
    
    
    
if __name__ == '__main__': 
    satyc2dat()